Introductory Pygmy Forth Tutorial for the Compleat Beginner (or is it An Incomplete Tutorial for An Incomplete Beginner?) Foot in the Door Here's the tricky part: what do _you_ need to know to learn Forth? If we cover it at too low a level you can say "Yeah, yeah, I already know all that, but I'm still stuck." If we cover it at too high a level then perhaps nothing will make any sense at. There is a _lot_ of information available about Forth in books, magazines, diskettes, and bulletin board messages. Much of this material is available through the Forth Interest Group (510-89-FORTH). You should join, or at least get their list of publications, and read as much as possible. At the very least you should study the book _Starting Forth_ by Leo Brodie and you should read the Pygmy Forth manual (the file PYGMY.TXT) and study its source code blocks and their shadows. RSVP If you are a beginner, or if you are "stuck" somewhere in your study of Forth, please study this tutorial and actually do the practice exercises, no matter how silly they sound. Then send me a report. I would like to know exactly what you are having trouble with, what makes sense and what doesn't. Tell me what you have tried and where it went wrong and where it went right. What do you think are the key points, which if explained better would make it all make sense? What are your major remaining questions or difficulties? I will attempt to respond in an upcoming magazine article. Disclaimer 1: This tutorial takes a single approach to introducing you to Forth. Right here, at the beginning, I wish to acknowledge that many other approaches could be taken. Having said that, I will omit the on-the-other-hands. Let's pretend for now there is only one right way to do it, and this is it. Disclaimer 2: This is a tutorial on Forth, specifically Pygmy Forth for MS/PC-DOS computers. It does not include information about how to use DOS or how to turn on your computer or warn you that you need to type a carriage return at the end of a command or explain what an .EXE or .COM or .BAT file is or how you can find the executable files on a disk or how to browse through ascii textfiles or what ascii means. I apologize in advance if I inadvertently touch on any of those subjects. ------------------------ The One Right Way: To master Forth you only need: A. a few broad, simple concepts B. a "cookbook" collection of examples C. a lifetime's worth of evaluating what you are doing and why ---------------------- A. A Few Broad, Simple Concepts ## Forth is modular. We do our work in little bitty pieces and pyramid them into simple, powerful, hierarchical structures. We should all adopt Rob Chapman's slogan "It's so simple it has to work." Our job is to _make_ it that simple and _keep_ it that simple. ## Forth is interactive. We build a little piece and test it immediately from the keyboard. The more we test early the less we are bitten later. ## Forth is not a religion. Unlike some languages I might mention, Forth is so simple we do not need to take it on faith. We can see it and test it, rather than having to "believe" and "hope" and "trust." We can inspect and modify any part of the system. Full source code is included, and is small enough, and modularly organized enough, to be manageable. I want to go over this point again because it is so radical it might be missed: Pygmy Forth includes _all_ of its own source code. You can actually understand it. You can study and modify the system. You can examine any part of the system you are curious about. This is virtually unheard of with any language except Forth. ## Forth has an explicit data stack. Take a stack of magazines and put them on the floor one at a time, one on top of the other. Which is the easiest to get to (the one on top)? Empty the stack and put one magazine down, saying "3" then put another magazine on top of it, saying "5." Ok, what's on the stack (3 and 5)? Which number is on top (5)? Now pretend you are the + (i.e. "plus" or addition) operator. It is your job to take two numbers off the stack, add them, and put the sum back onto the stack. Go ahead do it, take the 5 and 3 off the stack, add them to get 8, and put the 8 back on the stack. How many items are on the stack now (one) and what is it (8)? (Notice the "subliminal" hints in the previous questions, in case you are having trouble answering.) ## Forth has active operators. In the previous example, + _did_ something; it wasn't a parsing symbol to tell something else to do something. Forth words are active! They go to the stack to get the materials (numbers) they need, they do their work, then they place their results on the stack. ## Forth must be practiced Ok, you know enough now to start practicing with the computer. I hope you have printed out a hard copy of this file so you can read along while you run Pygmy on the computer. Go ahead, bring up Pygmy. Put some numbers on the stack by typing 1 3 5 7 9 followed by the carriage return (which I am _never_ going to mention again!). What is on the stack? What is on top? Type .S to display the contents of the stack and check to see if your answers were correct. Now type . and see what happens. Type .S and see if the stack is different. The dot removes the top item from the stack and prints it as a number. Play with putting numbers on the stack and removing them. ## Forth uses postfix notation. This should not surprise you since it is how + worked several paragraphs back. Postfix means you type the operator _after_ typing its operands. Try out these examples (and use . or .S to see the results): multiply 3 by 5 by typing 3 5 * subtract 7 from 9 by typing 9 7 - Note, the order of operands is exactly the same as you are used to in "infix", i.e. 3*5 or 9-7; the only difference is the operator goes after its operands instead of between them. Ok, continue. (3+5)*(6+2) by typing 3 5 + 6 2 + * 3+5 * 6+2 by typing 3 5 6 * + 2 + Postfix is simple, direct, doesn't require precedence rules, doesn't require parentheses. You'll get the hang of it in no time. Notice even in these complex examples that the order of the operands (the numbers) is the same in both the infix and the postfix versions. The last example above, due to the higher precedence of the infix multiply operator, is _not_ the equivalent of 8*8, but of 3+30+2. ## Forth uses one or more blanks to separate words in the input stream. A word is a group of non-blank characters. Generally speaking, the only things you feed Forth are words. Each word is one of three things: 1. A word already known to Forth (i.e. it is in Forth's dictionary), in which case Forth executes the word. 2. A word not in Forth's dictionary, but one that can be interpreted as a valid number (e.g. 75), in which case Forth does interpret it a number and pushes it to the stack. 3. Neither of the above, in which case Forth reports an error. Please re-read that. Isn't that simple? Isn't that pretty? Like the shark is a feeding machine, Forth is an executing engine. It gobbles input, pushing numbers to the stack, executing words which exist in the dictionary, and choking on anything else. It makes no difference whether you separate words with one space or 50, whether you put several words on one line or spread them across several lines. ## _You_ can add words to the dictionary. And, they are full citizens with equal standing to all the other words in the dictionary. To use this power responsibly, remember to add little bitty words and not great big unmanageable words. I do not mean its name should be short, but that its function should be simple, obvious, straightforward. We "divide and conquer" at the beginning rather than trying to debug a hopeless mess at the end. Do not make a word a jack of all trades. Make it a master of one. This process of adding a word to the dictionary is called defining a word. Several different types of words can be defined, but for now we will study a single type. This one type can be used for everything you need at first. This type of definition is called a colon definition, because the colon starts the definition, e.g. : SEVENTEEN 17 ; Type that in and see what happens. Nothing? Well, not nothing exactly, as you did get the "ok" prompt to indicate Forth gobbled it up with no complaints. The new word SEVENTEEN is now in the dictionary. Type SEVENTEEN and see what happens (use . or .S). So, what else would you expect it to do? It puts the number 17 on the stack. The definition begins with the word : which is followed by a blank because the colon is not a _symbol_ but an active word. You are used to numbers preceding a word that uses them (so they will be waiting on the stack). On the other hand, strings often follow the word that uses them. In this case : expects to find a string in the input stream, and it uses this string as the name of the new word it creates. Then colon collects all the other words up to the ; and stores them in the body of the new word. The semicolon is a special word in that it ends the definition. Try defining and executing the following until you get the hang of it: : 3* ( n - 3*n) 3 * ; 17 3* . 2 3* . 2 3* 3* 3* . : FEET ( feet - inches) 12 * ; 6 FEET . 5 FEET . : STAR ( -) ." *" ; STAR STAR STAR STAR : STARS ( # -) FOR STAR NEXT ; 0 STARS 1 STARS 2 STARS 200 STARS : DIGITS ( -) 0 10 FOR DUP . 1+ NEXT DROP ; DIGITS : DIGITS ( -) CR CR CR DIGITS CR CR CR ; Wow, have we got some explaining to do. Notice the comments in parentheses inside every definition such as ( n -). Notice how the left parenthesis is followed by a space. As you must be getting used to by now, the left parenthesis is a word, but one that is executed during the defining process. What does it do? It skips the input stream up through the ending parenthesis. Why do we put in comments? Several reasons. First, it is our minimum specification of what the word is intended to do. It shows what should be on the stack before and after the word executes. We need to know what the word should do as we write it and as we test it. For example, DIGITS takes nothing from the stack and places nothing on the stack. We call this comment a "stack comment" or a "stack picture". Get in the habit of putting this in every word you define. Notice the use of Forth's print statement in STAR. The ." (i.e. dot-quote) is a word, so it is followed by a space, then by whatever characters you want to display, then by an ending quote mark. FOR ... NEXT should be obvious. DUP copies the top of the stack, i.e. its stack comment would be ( n - n n). DROP drops the top item from the stack, i.e. ( n -). CR does a carriage return. Next, you try defining a word that prints your name. Then use that word in the definition of another word. Here's an example: : ME ( -) ." FRANK" ; (be sure to test it before you continue!) then : WHO? ( -) ME ." , THAT'S WHO!" CR ; ## Forth is case-sensitive. At least Pygmy and many others are case-sensitive. To test it try typing the following four lines to see which of them Forth executes and which it chokes on. CR cr cR Cr ## Review Where are words looked up (the dictionary)? Where do numbers go (the stack)? How long should a definition be (not very)? When should you test (immediately upon defining each word)? How do you find out how a particular Forth word works (look at its source and experiment with it from the keyboard)? There you have it. Those are the concepts you need. Everything else is simply a matter of asking "How do I do such and such?" and finding a cookbook example to copy, or better, to study and possibly modify. --------------------- The Cookbook Where do you find examples, and how do you answer questions about the Forth system? Type WORDS and see what happens. This displays the words in the dictionary. Did they scroll by too fast? Try it again and press any key to make it halt, and then press a key again to let it continue. When you see a word that interests you, such as EXPECT type VIEW EXPECT Bang, you are popped into the editor at the definition of EXPECT. You can read its definition, especially its stack comment. You can then use PgUp and PgDn to browse through nearby blocks of source code. If you have the shadow blocks for Pygmy you can press Ctrl-A to alternate between the block EXPECT is defined on, and its shadow block that gives more information. Speaking of the editor, type .FILES and see what happens. This shows the files that are currently available and the beginning and ending block numbers for each file and the DOS handle number. (If the handle number is shown as -1 then the file is not available.) Notice that PYGMY.SCR begins at block zero, so type 0 EDIT This file holds _all_ the source code for Pygmy. Browse through it with PgUp, PgDn, (and switch to and from the shadow file with Ctrl-A, if the shadow file is available). Do not worry too much about learning all the details of what you see. Right now you are just taking a tour to see what's where. Go ahead, browse awhile. Notice that the definitions of words usually have stack comments. Press Esc to get out of the editor. Between WORDS EDIT and VIEW you should be able to locate the source code for any word in the dictionary. Now here's where the Cookbook comes in: get into the editor at the first block or so (e.g. 1 EDIT) and then use the F3 (ie the function key F3) and the F10 keys to setup a search string for the word of interest and then search across blocks for it. This way you can find examples of how that word has been used within other definitions. You can learn a lot from doing that. Plus you will get more comfortable with Pygmy as a whole. However, until you are comfortable, until you are familiar with just how it works, you can refer to the following list of How-do-I-do-such-&-such questions to get going. Q: I am tired of defining words and having them scroll off the screen where I can no longer see the stack comment you made me write. Ditto for retyping the definition every time I restart Pygmy from DOS. A: That's not a question; that's a complaint. But, nevertheless, you are now ready to use the editor to save and change the source code you write. An entire file is setup just for your own code. It is named YOURFILE.SCR. You can see it listed when you type .FILES. Note that it starts at block 2000. Type 2000 EDIT and browse through it with PgDn and PgUp. All the blocks are blank, probably, unless you have already put stuff in them. See the documentation file PYGMY.TXT for instructions on using the editor, or use the quick reference reminder list on the status line at the top of the display and experiment. Type away to enter your source code. Then, to compile your source code, say from block 2002, get out of the editor by pressing Esc and type 2002 LOAD. To get back into the editor, you can type 2002 EDIT or you can just type ED to return to the last block edited. When you exit from Pygmy with BYE the words you've loaded will vanish from the dictionary, but their definitions will still be on block 2002. Next time you run Pygmy, you can easily reload those definitions without retyping them just by saying 2002 LOAD. Q: I'm tired even of typing 2002 LOAD to reload my favorite little additions every time I run Pygmy. Isn't there a way to avoid that step? A: At least you asked a question this time. Yes, there is a way. After you have loaded your favorite words, type SAVE A5.COM That creates an executable file similar to the one you started up Pygmy from, but named A5.COM. Of course you are free to invent other names if you don't like the sound of A5. But, the file extension should always be .COM. Next time you want to run Pygmy, run it by typing A5 from DOS. The dictionary will contain all your goodies. Q: How do I create a file in Pygmy? A: Why do you want to know? You already have a file for your source code blocks, i.e. YOURFILE.SCR. Just use it! Q: But it's full. It only has eight blocks and I've used them all up. A: Oh, well, that's simple. Get into the editor and move to the block where you want more room. Press the F9 key. The editor will ask you how many. Enter a number, such as 20. The editor will spread open the file at that point and insert 20 blank blocks right after the current block. Q: But, what if I want to use a _different_ file for some of my code? A: Ok, ok. There are several ways to do it. Just get out to DOS and type COPY YOURFILE.SCR NEWFILE.SCR then get back into Pygmy and type " NEWFILE.SCR" 4 OPEN SAVE A6.COM or, from within Pygmy you can create a new file by loading the definition of NEWFILE from block 136 and using it to create the new file, e.g. " NEWFILE.SCR" NEWFILE Well, that gives you the idea, I'm sure. Q: Can Pygmy load from textfiles? I'm more comfortable with them and with my favorite editor. A: What? Well, just practice with Pygmy's block editor until you become comfortable with _it_. But, the answer is yes, you can load textfiles with FLOAD or with INCLUDE. I'll leave it as an exercise for you to look up those words in PYGMY.SCR and/or to look up the discussion of textfile loading in the manual PYGMY.TXT. However, block files have a lot to offer over textfiles, such as their instant availability with the built-in editor, and their inherent modularity. You _are_ writing very small definitions, aren't you? Q: But I've seen some of _your_ source code and sometimes a single word damn near overflows an entire block. A: Don't do what I do; do what I say. Conclusion Do you feel oriented and comfortable yet (yes, I sure do, you've opened my eyes to the power and beauty of Forth!)? THE END